package com.huika.lib.encrypt;

import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.spec.KeySpec;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * 加解密统一接口，支持流行的对称和非对称算法 目前可以使用3DES,AES，RSA进行加解密
 * 
 * @author luis.chen
 * @version $Id: EncryptUtil.java, v 0.1 2014年6月17日 上午11:08:28 luis.chen Exp $
 */
public class EncryptUtil {

	public static void main(String args[]) {
		String plainText = "{\"userId\":\"100593\"}";
		try {

			System.out.println("开始使用AES加密....");
			// 使用AES加密
//			byte[] asKey = getDefaultKey(EncryptAlgorithm.AES);
			Base64Encoder enc = new Base64Encoder();
//			String t = enc.encode(asKey);
			String t = "ckUdE8bGyiID2pZjP82gqA==";
			byte asKey[] = Base64.decode(t);

			System.out.println("AES秘钥：" + t);
			String encStr = testSymmEncry(plainText, asKey,
					EncryptAlgorithm.AES);
			System.out.println("AES加密之后:" + encStr);
			// 使用AES解密
			String decStr = testSymmDecry(encStr, asKey, EncryptAlgorithm.AES);
			System.out.println("AES解密之后:" + decStr);

			System.out.println("开始使用RSA加密....");

			KeyPair kp = getDefaultKeyPair(EncryptAlgorithm.RSA);
			String rsaEncStr = testAsymmEncry(plainText, kp.getPublic(),
					EncryptAlgorithm.RSAWithPadding);

			System.out.println("RSA加密之后:" + rsaEncStr);
			// 使用RSA解密
			String desDecStr = testAsymmDecry(rsaEncStr, kp.getPrivate(),
					EncryptAlgorithm.RSAWithPadding);
			System.out.println("RSA解密之后:" + desDecStr);

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public static String testSymmEncry(String plainText, byte[] key,
			EncryptAlgorithm alg) throws Exception {
		/* 测试对称加密方法的应用场景类 */
		byte[] encResult = encryt(
				EncryptStringUtils.getEncByteFromStr(plainText), key, alg);
		String encStr = EncryptStringUtils.byte2hex(encResult);
		return encStr;
	}

	public static String testAsymmEncry(String plainText, Key key,
			EncryptAlgorithm alg) throws Exception {
		/* 测试非对称加密方法的应用场景类 */
		// byte[] encResult =
		// encryt(EncryptStringUtils.getEncByteFromStr(plainText),key,alg);
		byte[] encResult = encryt(plainText.getBytes(), key, alg);
		String encStr = EncryptStringUtils.byte2hex(encResult);
		return encStr;
	}

	public static String testSymmDecry(String ciperText, byte[] key,
			EncryptAlgorithm alg) throws Exception {
		/* 测试解密方法的应用场景类 */
		byte[] decResult = decryt(
				EncryptStringUtils.getDecByteFromStr(ciperText), key, alg);
		String decStr = new String(decResult);
		return decStr;
	}

	public static String testAsymmDecry(String ciperText, Key key,
			EncryptAlgorithm alg) throws Exception {
		/* 测试非对称解密方法的应用场景类 */
		byte[] decResult = decryt(
				EncryptStringUtils.getDecByteFromStr(ciperText), key, alg);
		String decStr = new String(decResult);
		return decStr;
	}

	/**
	 * 对称加密方法
	 * 
	 * @param plainText
	 *            明文的16进制字节数组
	 * @param encrytKey
	 *            16进制的密钥数组
	 * @param alg
	 *            加密算法的枚举
	 * @return 加密结果，返回加密后的字节数组
	 * @throws Exception
	 * */
	public static byte[] encryt(byte[] plainText, byte[] encrytKey,
			EncryptAlgorithm alg) throws Exception {
		Key k = toKey(encrytKey, alg);
		return encryt(plainText, k, alg);
	}

	/**
	 * 非对称加密方法
	 * 
	 * @param plainText
	 *            明文的16进制字节数组
	 * @param key
	 *            通过KeyPair获得的公钥
	 * @param alg
	 *            加密算法的枚举
	 * @return 加密结果，返回加密后的字节数组
	 * @throws Exception
	 * */
	public static byte[] encryt(byte[] plainText, Key key, EncryptAlgorithm alg)
			throws Exception {
		Cipher cipher = Cipher.getInstance(alg.getAlgorithm());
		cipher.init(Cipher.ENCRYPT_MODE, key);
		return cipher.doFinal(plainText);
	}

	/**
	 * 对称加密解密方法
	 * 
	 * @param ciperText
	 *            密文的16进制字节数组
	 * @param decrytKey
	 *            16进制的密钥数组
	 * @param alg
	 *            加密算法的枚举
	 * @return 解密结果，返回解密后的字节数组
	 * @throws Exception
	 * */
	public static byte[] decryt(byte[] ciperText, byte[] decrytKey,
			EncryptAlgorithm alg) throws Exception {
		Key k = toKey(decrytKey, alg);
		return decryt(ciperText, k, alg);
	}

	/**
	 * 非对称加密解密方法
	 * 
	 * @param ciperText
	 *            密文的16进制字节数组
	 * @param key
	 *            通过keypair得到的非对称加密私钥
	 * @param alg
	 *            加密算法的枚举
	 * @return 解密结果，返回解密后的字节数组
	 * @throws Exception
	 * */
	public static byte[] decryt(byte[] ciperText, Key key, EncryptAlgorithm alg)
			throws Exception {
		Cipher cipher = Cipher.getInstance(alg.getAlgorithm());
		cipher.init(Cipher.DECRYPT_MODE, key);
		return cipher.doFinal(ciperText);
	}

	/**
	 * 获取对称加密算法算法的密钥
	 * 
	 * @param alg
	 *            加密算法枚举
	 * @return 16进制的密钥数组
	 * @throws
	 * */
	public static byte[] getDefaultKey(EncryptAlgorithm alg) throws Exception {
		KeyGenerator keygen = KeyGenerator.getInstance(alg.getAlgorithm());
		SecretKey deskey = keygen.generateKey();
		return deskey.getEncoded();
	}

	/**
	 * 获取非对称加密算法的密钥
	 * 
	 * @param alg
	 *            加密算法枚举
	 * @return 16进制的密钥数组
	 * @throws
	 * */
	public static KeyPair getDefaultKeyPair(EncryptAlgorithm alg)
			throws Exception {
		KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(alg
				.getAlgorithm());
		// 密钥位数
		keyPairGen.initialize(1024);
		// 密钥对
		KeyPair keyPair = keyPairGen.generateKeyPair();
		return keyPair;
	}

	/**
	 * 通过key的字节数组和特定的算法得到用于加解密的密钥对象
	 * 
	 * @param key
	 *            密钥数组
	 * @param alg
	 *            加解密算法的枚举
	 * @return KEY
	 * @throws Exception
	 */
	private static Key toKey(byte[] key, EncryptAlgorithm alg) throws Exception {
		SecretKeySpec spec = new SecretKeySpec(key, alg.getAlgorithm());
		if (alg.getAlgorithm().indexOf("DES") > -1) {
			KeySpec desKey = null;
			SecretKeyFactory keyFactory = null;
			if ("DES".equals(alg.getAlgorithm())) {
				desKey = new DESKeySpec(key);
				keyFactory = SecretKeyFactory.getInstance(alg.getAlgorithm());
			} else {
				desKey = new DESedeKeySpec(key);
				keyFactory = SecretKeyFactory
						.getInstance(EncryptAlgorithm.ThreeDES.getAlgorithm());
			}// 将DESKeySpec对象转换成SecretKey对象
			SecretKey securekey = keyFactory.generateSecret(desKey);
			return securekey;
		}

		return spec;
	}

}
